package utils

import (
	"bytes"
	"context"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"go_web/internal/global"
	"go_web/internal/model"
	"go_web/internal/model/model_sys"
	"go_web/internal/repo/repo_sys"
	"go_web/pkg/config"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	"github.com/redis/go-redis/v9"
	"github.com/samber/lo"
)

// 自定义的 Claims 结构体，嵌入到 jwt.RegisteredClaims
type CustomClaims struct {
	UserId        int64  `json:"user_id"`
	RefreshSecret string `json:"refresh_secret"`
	jwt.RegisteredClaims
}

func GenerateToken(userId int64) (model.Token, error) {
	cfg := config.Get()
	timeout := time.Duration(cfg.Jwt.Timeout) * time.Second
	now := time.Now()
	accessExpiration := now.Add(timeout)
	refreshExpiration := now.Add(timeout * 2)

	// accessToken
	accessClaims := CustomClaims{
		UserId: userId,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(accessExpiration),
			IssuedAt:  jwt.NewNumericDate(now),
			NotBefore: jwt.NewNumericDate(now),
			Issuer:    "go-web",
		},
	}

	accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, accessClaims)
	accessTokenStr, err := accessToken.SignedString([]byte(cfg.Jwt.Secret))
	if err != nil {
		return model.Token{}, fmt.Errorf("failed to generate access token: %w", err)
	}

	// refreshToken
	refreshClaims := CustomClaims{
		UserId:        userId,
		RefreshSecret: cfg.Jwt.RefreshSecret,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(refreshExpiration),
			IssuedAt:  jwt.NewNumericDate(now),
			NotBefore: jwt.NewNumericDate(now),
			Issuer:    "go-web",
		},
	}

	refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, refreshClaims)
	refreshTokenStr, err := refreshToken.SignedString([]byte(cfg.Jwt.Secret))
	if err != nil {
		return model.Token{}, fmt.Errorf("failed to generate refresh token: %w", err)
	}

	// 关键修改：将时间戳改为毫秒级
	token := model.Token{
		AccessToken:  accessTokenStr,
		RefreshToken: refreshTokenStr,
		TokenTimes: model.TokenTimes{
			IssuedAt:          now.UnixMilli(),               // 改为毫秒级
			Expiration:        accessExpiration.UnixMilli(),  // 改为毫秒级
			Expire:            cfg.Jwt.Timeout * 1000,        // 毫秒数 = 秒数 * 1000
			RefreshExpiration: refreshExpiration.UnixMilli(), // 改为毫秒级
		},
	}

	return token, nil
}

// 验证Access Token
func ValidateAccessToken(tokenStr string) (*CustomClaims, error) {
	cfg := config.Get()
	token, err := jwt.ParseWithClaims(tokenStr, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		// 验证签名方法
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(cfg.Jwt.Secret), nil

	})
	if err != nil {
		return nil, fmt.Errorf("token parsing failed: %v", err)
	}

	if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
		// 额外的验证逻辑
		if claims.Issuer != "go-web" {
			return nil, fmt.Errorf("invalid issuer")
		}
		return claims, nil
	}

	return nil, fmt.Errorf("invalid token")
}

// 验证Refresh Token
func ValidateRefreshToken(tokenString string) (*CustomClaims, error) {
	cfg := config.Get()

	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		// 验证签名方法
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(cfg.Jwt.Secret), nil
	})

	if err != nil {
		return nil, fmt.Errorf("refresh token parsing failed: %v", err)
	}

	if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
		// 验证refresh token的特殊逻辑
		if claims.Issuer != "go-web" {
			return nil, fmt.Errorf("invalid issuer")
		}
		if claims.RefreshSecret != cfg.Jwt.RefreshSecret {
			return nil, fmt.Errorf("invalid refresh secret")
		}
		return claims, nil
	}

	return nil, fmt.Errorf("invalid refresh token")
}

// 刷新Token（使用refresh token获取新的access token）
func RefreshAccessToken(refreshTokenString string) (model.Token, error) {
	// 验证refresh token
	claims, err := ValidateRefreshToken(refreshTokenString)
	if err != nil {
		return model.Token{}, fmt.Errorf("invalid refresh token: %v", err)
	}

	// 生成新的access token
	return GenerateToken(claims.UserId)
}

// 获取Token中的用户ID
func GetUserIdFromToken(tokenString string) (int64, error) {
	claims, err := ValidateAccessToken(tokenString)
	if err != nil {
		return 0, err
	}
	return claims.UserId, nil
}

func GetTokenFromHeader(c *gin.Context) (*string, error) {
	authHeader := c.Request.Header.Get("Authorization")
	fmt.Println("authHeader", authHeader)
	if authHeader == "" {
		return nil, fmt.Errorf("Authorization header is empty")
	}
	// 提取 Token 字符串
	parts := strings.SplitN(authHeader, " ", 2)
	if len(parts) != 2 || parts[0] != "Bearer" {
		return nil, fmt.Errorf("Authorization header is empty")
	}
	token := parts[1]
	return &token, nil
}

func GetRefreshTokenFromHeader(c *gin.Context) (*string, error) {
	authHeader := c.Request.Header.Get("X-Refresh-Token")
	fmt.Println("authHeader", authHeader)
	if authHeader == "" {
		return nil, fmt.Errorf("X-Refresh-Token header is empty")
	}
	// 提取 Token 字符串
	parts := strings.SplitN(authHeader, " ", 2)
	if len(parts) != 2 || parts[0] != "Bearer" {
		return nil, fmt.Errorf("X-Refresh-Token header is empty")
	}
	token := parts[1]
	return &token, nil
}

// 检查Token是否即将过期（用于提前刷新）
func IsTokenExpiringSoon(tokenString string, threshold time.Duration) (bool, error) {
	claims, err := ValidateAccessToken(tokenString)
	if err != nil {
		return false, err
	}

	expirationTime := claims.ExpiresAt.Time
	now := time.Now()

	return expirationTime.Sub(now) <= threshold, nil
}

// 记录登录凭证（如果 redis 中没有，那么就代表已经下线）
func LoginAtRedis(c context.Context, accessToken string, userId int64, threshold time.Duration) error {
	sysUserRoleMapList, err := repo_sys.SysUserRoleMap.Where(repo_sys.SysUserRoleMap.UserID.Eq(userId)).Find()

	if err != nil {
		return err
	}
	redisMap := make(map[string]interface{}, 0)
	roleList := make([]string, len(sysUserRoleMapList))
	for k, v := range sysUserRoleMapList {
		roleList[k] = v.Role
	}
	redisMap["ROLE_LIST"] = roleList

	if err != nil {
		return err
	}

	dataScopeList, err := repo_sys.SysDataScope.Where(repo_sys.SysDataScope.Or(
		repo_sys.SysDataScope.TargetID.Eq(userId),
		repo_sys.SysDataScope.Role.In(roleList...))).Find()
	if err != nil {
		return err
	}
	redisMap["DATA_SCOPE_LIST"] = dataScopeList

	// 直接缓存 DATA_SCOPE_ORG_SUB 权限
	dataScopeOrg, err := repo_sys.SysOrgUser.Where(repo_sys.SysOrgUser.OrgID.Eq(userId)).Find()
	if err != nil {
		return err
	}
	if dataScopeOrg != nil && len(dataScopeOrg) > 0 {
		dataScopeOrgIdList := lo.Map(dataScopeOrg, func(item *model_sys.SysOrgUser, index int) int64 {
			return item.ID
		})
		orgHierarchy, err := repo_sys.SysOrg.FindOrgHierarchy(dataScopeOrgIdList)
		if err != nil {
			return err
		}
		orgSub := lo.Map(orgHierarchy, func(item *model_sys.SysOrg, index int) int64 {
			return item.ID
		})
		redisMap["DATA_SCOPE_ORG_SUB"] = orgSub
		redisMap["DATA_SCOPE_ORG"] = dataScopeOrg
	}

	// 转为 JSON 字符串
	redisMapStr, err := json.Marshal(redisMap)
	// 存入 Redis
	ret := global.Redis.Set(c, fmt.Sprintf("token::%s", accessToken), string(redisMapStr), threshold)

	if ret.Err() == redis.Nil {
		return errors.New("token does not exist")
	}
	return nil
}

func GetRoleListByToken(c context.Context, accessToken string) ([]string, error) {
	redisRet := global.Redis.Get(c, fmt.Sprintf("token::%s", accessToken))
	if redisRet.Err() == redis.Nil {
		return []string{}, errors.New("token does not exist")
	}
	var retMap map[string]interface{}
	bytes, err := redisRet.Bytes()
	if err != nil {
		return []string{}, err
	}
	err = json.Unmarshal(bytes, &retMap)
	if err != nil {
		return []string{}, err
	}

	// 修复类型断言
	roleInterface, ok := retMap["ROLE_LIST"]
	if !ok {
		return []string{}, errors.New("role_list not found in token data")
	}

	// 将 []interface{} 转换为 []string
	roleInterfaceSlice, ok := roleInterface.([]interface{})
	if !ok {
		return []string{}, errors.New("role_list is not a valid array")
	}

	roles := make([]string, len(roleInterfaceSlice))
	for i, v := range roleInterfaceSlice {
		role, ok := v.(string)
		if !ok {
			return []string{}, fmt.Errorf("role_list contains non-string value at index %d", i)
		}
		roles[i] = role
	}

	return roles, nil
}

// 从 Token 中获取 DATA_SCOPE_LIST
func GetDataScopeListByToken(c context.Context, accessToken string) ([]model_sys.SysDataScope, error) {
	redisRet := global.Redis.Get(c, fmt.Sprintf("token::%s", accessToken))
	if redisRet.Err() == redis.Nil {
		return []model_sys.SysDataScope{}, errors.New("token does not exist")
	}
	var retMap map[string]interface{}
	bytes, err := redisRet.Bytes()
	if err != nil {
		return []model_sys.SysDataScope{}, err
	}
	err = json.Unmarshal(bytes, &retMap)
	if err != nil {
		return []model_sys.SysDataScope{}, err
	}

	// 修复类型断言
	dataScopeListInterface, ok := retMap["DATA_SCOPE_LIST"]
	if !ok {
		return []model_sys.SysDataScope{}, errors.New("data_scope_list not found in token data")
	}

	// 将 []interface{} 转换为 []model_sys.SysDataScope
	dataScopeListInterfaceSlice, ok := dataScopeListInterface.([]interface{})
	if !ok {
		return []model_sys.SysDataScope{}, errors.New("data_scope_list is not a valid array")
	}

	dataScopeList := make([]model_sys.SysDataScope, len(dataScopeListInterfaceSlice))
	for i, v := range dataScopeListInterfaceSlice {
		dataScope, ok := v.(model_sys.SysDataScope)
		if !ok {
			return []model_sys.SysDataScope{}, fmt.Errorf("data_scope_list contains non-string value at index %d", i)
		}
		dataScopeList[i] = dataScope
	}

	return dataScopeList, nil
}

// 从 Token 中获取 DATA_SCOPE_ORG_SUB
func GetDataScopeOrgSubByToken(c context.Context, accessToken string) ([]int64, error) {
	redisRet := global.Redis.Get(c, fmt.Sprintf("token::%s", accessToken))
	if redisRet.Err() == redis.Nil {
		return []int64{}, errors.New("token does not exist")
	}
	var retMap map[string]interface{}
	bytes, err := redisRet.Bytes()
	if err != nil {
		return []int64{}, err
	}
	err = json.Unmarshal(bytes, &retMap)
	if err != nil {
		return []int64{}, err
	}

	// 修复类型断言
	dataScopeOrgSubInterface, ok := retMap["DATA_SCOPE_ORG_SUB"]
	if !ok {
		return []int64{}, errors.New("data_scope_org_sub not found in token data")
	}

	// 将 []interface{} 转换为 []int64
	dataScopeOrgSubInterfaceSlice, ok := dataScopeOrgSubInterface.([]interface{})
	if !ok {
		return []int64{}, errors.New("data_scope_org_sub is not a valid array")
	}

	dataScopeOrgSub := make([]int64, len(dataScopeOrgSubInterfaceSlice))
	for i, v := range dataScopeOrgSubInterfaceSlice {
		id, ok := v.(int64)
		if !ok {
			return []int64{}, fmt.Errorf("data_scope_org_sub contains non-string value at index %d", i)
		}
		dataScopeOrgSub[i] = id
	}

	return dataScopeOrgSub, nil
}

// 从 Token 中获取 DATA_SCOPE_ORG
func GetDataScopeOrgByToken(c context.Context, accessToken string) ([]int64, error) {
	redisRet := global.Redis.Get(c, fmt.Sprintf("token::%s", accessToken))
	if redisRet.Err() == redis.Nil {
		return []int64{}, errors.New("token does not exist")
	}
	var retMap map[string]interface{}
	bytes, err := redisRet.Bytes()
	if err != nil {
		return []int64{}, err
	}
	err = json.Unmarshal(bytes, &retMap)
	if err != nil {
		return []int64{}, err
	}

	// 修复类型断言
	dataScopeOrgInterface, ok := retMap["DATA_SCOPE_ORG"]
	if !ok {
		return []int64{}, errors.New("data_scope_org not found in token data")
	}

	// 将 []interface{} 转换为 []int64
	dataScopeOrgInterfaceSlice, ok := dataScopeOrgInterface.([]interface{})
	if !ok {
		return []int64{}, errors.New("data_scope_org is not a valid array")
	}

	dataScopeOrg := make([]int64, len(dataScopeOrgInterfaceSlice))
	for i, v := range dataScopeOrgInterfaceSlice {
		id, ok := v.(int64)
		if !ok {
			return []int64{}, fmt.Errorf("data_scope_org contains non-string value at index %d", i)
		}
		dataScopeOrg[i] = id
	}

	return dataScopeOrg, nil
}

func GetOrgIDListFromRedis() ([]int64, error) {
	ctx := context.Background()

	// 从 Redis 获取数据
	orgIdListJson, err := global.Redis.Get(ctx, "go_web:org:id:list").Result()
	if err != nil {
		return nil, err
	}

	// 解析 JSON 到切片
	var orgIdList []int64
	err = json.Unmarshal([]byte(orgIdListJson), &orgIdList)
	if err != nil {
		return nil, err
	}

	return orgIdList, nil
}

// AES 加密
func AesEncrypt(oring string, key string) (string, error) {
	origData := []byte(oring)
	k := []byte(key)
	block, err := aes.NewCipher(k)
	if err != nil {
		return "", err
	}
	blockSize := block.BlockSize()
	origData = PKCS7Padding(origData, blockSize)
	blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
	encrypted := make([]byte, len(origData))
	blockMode.CryptBlocks(encrypted, origData)
	return base64.StdEncoding.EncodeToString(encrypted), nil
}

func PKCS7Padding(data []byte, blockSize int) []byte {
	padding := blockSize - len(data)%blockSize
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(data, padText...)
}

// AES 解密
func AesDecrypt(encrypted string, key string) (string, error) {
	encryptedData, err := base64.StdEncoding.DecodeString(encrypted)
	k := []byte(key)
	block, err := aes.NewCipher(k)
	if err != nil {
		return "", err
	}
	blockSize := block.BlockSize()
	blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
	decrypted := make([]byte, len(encryptedData))
	blockMode.CryptBlocks(decrypted, encryptedData)
	return string(PKCS7UnPadding(decrypted)), nil
}
func PKCS7UnPadding(data []byte) []byte {
	length := len(data)
	unpadding := int(data[length-1])
	return data[:(length - unpadding)]
}
